import draw.*;
import geometry.*;
import java.util.*;
import colors.*;
import tester.*;

/**
 * @author Ryan Cassidy & Adam Blackwell
 */
// Examples method tests the various part of the game functionality.
@Example
class Examples{
	Examples(){}

	//  Main method
	public static void main(String[] args){
		// construct an instance of a TimerWorld
		Examples w = new Examples();
		// and run the TimerWorld
		w.go();
	}

	boolean go(){
		return this.ex1.bigBang(1000, 600, 0.007);
	}   

	/**
	 * @uml.property  name="t1"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	Tile t1 = new Tile(new Posn(15, 15),new Red());
	/**
	 * @uml.property  name="t2"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	Tile t2 = new Tile(new Posn(0, 0), new Red());
	/**
	 * @uml.property  name="t4"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	Tile t4 = new Tile(new Posn(800, 1500), new Blue());

	/**
	 * @uml.property  name="lot1"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	ITileList lot1 = new MTLot();
	/**
	 * @uml.property  name="lot2"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	ITileList lot2 = 
		new ConsLot(new Tile(new Posn(15,-30),new Red()),
				new ConsLot(new Tile(new Posn(75,-30),new Red()),
						new ConsLot(new Tile(new Posn(165,-30),new Red()),
								new MTLot())));
	/**
	 * @uml.property  name="lot3"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	ITileList lot3 =                           
		new ConsLot(new Tile(new Posn(15,30),new Red()),
				new ConsLot(new Tile(new Posn(75,30),new Red()),
						new ConsLot(new Tile(new Posn(165,30),new Red()),
								new MTLot())));
	/**
	 * @uml.property  name="lot4"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	ITileList lot4 = new ConsLot(t1, new ConsLot(t2, new MTLot()));

	/**
	 * @uml.property  name="p1"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	Player p1 = new Player(new Posn(512, 580),5,new Green());
	/**
	 * @uml.property  name="p2"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	Player p2 = new Player(new Posn(512, 500),3,new Blue());
	/**
	 * @uml.property  name="p3"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	Player p3 = new Player(new Posn(15, 15),5, new White());

	/**
	 * @uml.property  name="ex1"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	GameWorld ex1 = new GameWorld(this.lot1,this.p1, 0);
	/**
	 * @uml.property  name="ex2"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	GameWorld ex2 = new GameWorld(this.lot2,this.p1, 0);
	/**
	 * @uml.property  name="ex3"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	GameWorld ex3 = new GameWorld(this.lot3,this.p2, 0);

	/*
	 *  Test these methods:
	 *      Tile: 
	 *      ConsLot : 
	 *      Player: 
	 *      Gameworld : ontick, addrow, maketile
	 * 
	 */

	// Just trying stuff...
	// draws the tiles onto the canvas
	boolean drawTiles(Canvas c, GameWorld ex){
		return this.ex3.lot.draw(c);
	}
	// draws the player onto the board
	boolean drawPlayer(Canvas c, GameWorld ex){
		return this.ex3.p.draw(c);
	}

	// Calls the above two methods?
	boolean drawStuff(Canvas c){
		return this.drawTiles(c, this.ex3) &&
		this.drawPlayer(c, this.ex3);
	}

	/**
	 * @uml.property  name="c"
	 * @uml.associationEnd  multiplicity="(1 1)"
	 */
	Canvas c = new Canvas(1000, 600);

	//Tests the center() method in the classes Player and Tile
	@TestMethod
	public void testCenter(Tester t){
		t.checkExpect(this.t1.center(), new Posn(20, 25));
		t.checkExpect(this.t2.center(), new Posn(5, 10));
		t.checkExpect(this.p1.center(), new Posn(517, 585));
	}

	//Tests the distanceToX() and distanceToY() methods in the class Tile
	@TestMethod
	public void testDistances(Tester t){
		t.checkExpect(this.t1.distanceToX(p1), 497.0);
		t.checkExpect(this.t2.distanceToX(p1), 512.0);
		t.checkExpect(this.t1.distanceToY(p1), 560.0);
		t.checkExpect(this.t2.distanceToY(p2), 495.0);
	}

	//Tests the hitp() methods in the classes Tile and ConsLot
	@TestMethod
	public void testHitp(Tester t){ 
		t.checkExpect(t1.hitp(p1), false);
		t.checkExpect(t1.hitp(p3), true);
		t.checkExpect(lot1.hitp(p1), false);
		t.checkExpect(lot4.hitp(p3), true);
	}

	// Tests the hitGround() methods for the tiles.
	@TestMethod
	public void testHitGroundp(Tester t){
		t.checkExpect(t1.hitGroundp(), false);
		t.checkExpect(t4.hitGroundp(), true);
	}

	// Tests the arrow keys and there responses. 
	@TestMethod
	public void testOnKeyEvent(Tester t){
		t.checkExpect(p3.onKeyEvent("x"), new Player(new Posn(15, 15), 5, new White()));
		t.checkExpect(p3.onKeyEvent("up"), new Player(new Posn(15, 9), 5, new White()));
		t.checkExpect(p3.onKeyEvent("down"), new Player(new Posn(15, 21), 5, new White()));
		t.checkExpect(p3.onKeyEvent("left"), new Player(new Posn(9, 15), 5, new White()));
		t.checkExpect(p3.onKeyEvent("right"), new Player(new Posn(21, 15), 5, new White()));
		t.checkExpect(p2.onKeyEvent("x"), new Player(new Posn(512, 500),3,new Blue()));
		t.checkExpect(p2.onKeyEvent("right"), new Player(new Posn(518, 500),3,new Blue()));
	}

	// Tests onTick in player tile and lot classes.
	@TestMethod
	public void testOnTick(Tester t){
		t.checkExpect(p1.onTick(), p1);
		t.checkExpect(t1.onTick(), new Tile(new Posn(15, 16), new Red()));
		t.checkExpect(lot4.onTick(), new ConsLot(new Tile(new Posn(15, 16), new Red()),
				new ConsLot(new Tile(new Posn(0, 1), new Red()), new MTLot())));
		t.checkExpect(ex1.onTick(),
				new GameWorld(new MTLot(), ex1.p, 1));
	}
	
	// Tests the draw method in GameWorld.
	@TestMethod
	public void testDraw(Tester t){
		t.checkExpect(p1.draw(c), true);
		t.checkExpect(p2.draw(c), true);
		t.checkExpect(p3.draw(c), true);
		t.checkExpect(lot1.draw(c), true);
		t.checkExpect(lot2.draw(c), true);
		t.checkExpect(lot3.draw(c), true);
		t.checkExpect(ex1.draw(), true);
		t.checkExpect(ex2.draw(), true);
		t.checkExpect(ex3.draw(), true);
	}
}